#include "MainWindow.h"
#include <QtGui/QtEvents>

namespace SQLDoc
{
	MainWindow::MainWindow( QWidget* parent /*= 0*/, Qt::WFlags flags /*= 0*/ ) : QMainWindow(parent, flags)
	{
		setupUi(this);

		m_tabs->setStartPage(m_startPage);

		/* Cannot delete first page from designer - this is done below */
		//while(m_tabs->count())
		//{
		//	QWidget *page = m_tabs->widget(0);
		//	m_tabs->removeTab(0);
		//	delete page;
		//}

		/* Setting up last connections list */
		loadLastConnectionList();
		refreshStartPage();

		/* Setting up menus */
		m_connectionMenu = createConnectionContextMenu();
		m_databaseMenu = createDatabaseContextMenu();
		m_tableMenu = createTableContextMenu();

		m_root = new DBObject(DBObject::DBOTYPE_ROOT, "ROOT", -1);

		m_connectionTreeModel = new ConnectionTreeModel();
		m_connectionTreeModel->setRootItem(m_root);
		m_connectionTreeModel->installEventFilter(this);

		m_connectionsTreeView->setModel(m_connectionTreeModel);
		m_connectionsTreeView->setContextMenuPolicy(Qt::CustomContextMenu);

		/* Connecting slots */
		connect(m_addConnectionButton, SIGNAL(clicked()), this, SLOT(addConnection_triggered()));
		connect(m_connectionsTreeView, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showContextMenu(const QPoint &)));
		connect(m_connectionsTreeView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(connectionsTreeView_clicked(const QModelIndex&)));
		connect(m_connectionsTreeView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(connectionsTreeView_doubleClicked(const QModelIndex&)));
		connect(m_tabs, SIGNAL(tabsChanged(int)), this, SLOT(window_tabsChanged(int)));

		/* Top menu */
		connect(m_addConnectionAction, SIGNAL(triggered(void)), this, SLOT(addConnection_triggered(void)));
		connect(m_connectionsAction, SIGNAL(triggered(void)), this, SLOT(connectionsVisible_triggered(void)));
		connect(m_startPageAction, SIGNAL(triggered(void)), this, SLOT(startPageVisible_triggered(void)));
	}

	MainWindow::~MainWindow()
	{ 
		saveLastConnectionList();

		if (m_connectionMenu)
			delete m_connectionMenu;
		if (m_databaseMenu)
			delete m_databaseMenu;
		if (m_tableMenu)
			delete m_tableMenu;
	}

	QSqlError MainWindow::connectToSqlServer(const QString &driver, const QString &sqlEngine, const QString &hostname, const QString &username, const QString &password, const int &port, QString &conName)
	{
		static int cCount = 0;
		QSqlError err;
		conName = QString(AppSettings::CONNECTION_NAME_FORMAT).arg(++cCount);
		QSqlDatabase db = QSqlDatabase::addDatabase(driver, conName);

		if(driver == "QMYSQL")
		{
			db.setHostName(hostname);
			db.setUserName(username);
			db.setPassword(password);

			int realPort = port;
			if(realPort == -1)
			{
				realPort = AppSettings::DEF_PORT_MYSQL;
			}
			db.setPort(realPort);
		}
		else if (driver.contains("QODBC"))
		{
			QString strDatabaseName = "DRIVER={" + sqlEngine + "};SERVER=" + hostname + ";UID=" + username + ";PWD=" + password + ";";

			db.setHostName(hostname);

			if (sqlEngine.contains("MySQL"))
				strDatabaseName.append("OPTION=3;");

			if(port != -1)
				db.setPort(port);

			db.setDatabaseName(strDatabaseName);
		}
		else
		{
			QMessageBox::warning(this, "Error", "No driver specified");
		}

		// Open connection
		if (!db.open(username, password)) {
			err = db.lastError();
			db = QSqlDatabase();
			QSqlDatabase::removeDatabase(conName);
		}
		else
		{
			addLastConnection(driver, sqlEngine, hostname, username, password, port);
			refreshStartPage();
		}

		return err;
	}

	void MainWindow::addConnectionToTree(const QString &driver, const QString &sqlEngine, const QString &hostname, const QString &username, const QString &password, const int &port, const QString &conName)
	{
		if (driver.contains("QODBC"))
		{
			if (sqlEngine.contains("SQL Server") || sqlEngine.contains("SQL Native"))
			{
				MSSQLConnection* connection = new MSSQLConnection();
				connection->setName(driver + "\\" + hostname);
				connection->setConnectionName(conName);
				reinterpret_cast<ConnectionTreeModel*>(m_connectionsTreeView->model())->addConnection(connection);
			}
			else if (sqlEngine.contains("MySQL"))
			{
				MySQLConnection* connection = new MySQLConnection();
				connection->setName(driver + "\\" + hostname);
				connection->setConnectionName(conName);
				reinterpret_cast<ConnectionTreeModel*>(m_connectionsTreeView->model())->addConnection(connection);
			}
		}
		else if (driver == "QMYSQL")
		{
			MySQLConnection* connection = new MySQLConnection();
			connection->setName(driver + "\\" + hostname);
			connection->setConnectionName(conName);
			reinterpret_cast<ConnectionTreeModel*>(m_connectionsTreeView->model())->addConnection(connection);
		}
	}

	QMenu* MainWindow::createConnectionContextMenu(void)
	{
		QMenu *menu = new QMenu();

		QAction *aCloseConnection = new QAction(QIcon(QString::fromUtf8(":/ico/close_ico16.png")), "Close connection", menu);
		QAction *aRefresh = new QAction(QIcon(QString::fromUtf8(":/ico/refresh_ico16.png")), "Refresh", menu);

		connect(aCloseConnection, SIGNAL(triggered(void)), this, SLOT(closeConnection_triggered(void)));
		connect(aRefresh, SIGNAL(triggered(void)), this, SLOT(refreshConnection_triggered(void)));

		menu->addAction(aCloseConnection);
		menu->addAction(aRefresh);

		return menu;
	}

	QMenu* MainWindow::createDatabaseContextMenu(void)
	{
		QMenu *menu = new QMenu();

		QAction *aRefreshDatabase = new QAction(QIcon(QString::fromUtf8(":/ico/refresh_ico16.png")), "Refresh", menu);

		connect(aRefreshDatabase, SIGNAL(triggered(void)), this, SLOT(refreshDatabase_triggered(void)));

		menu->addAction(aRefreshDatabase);

		return menu;
	}

	QMenu* MainWindow::createTableContextMenu(void)
	{
		QMenu *menu = new QMenu();

		QAction *aTableDetails = new QAction(QIcon(QString::fromUtf8(":/ico/table_ico16.png")), "Show details", menu);

		connect(aTableDetails, SIGNAL(triggered(void)), this, SLOT(tableDetails_triggered(void)));

		menu->addAction(aTableDetails);

		return menu;
	}

	void MainWindow::refreshStartPage(void)
	{
		/* Cleaning previous list */
		for (int i = m_scrollAreaWidgetContents->children().count() - 1; i >= 0; i--)
		{
			QWidget *widget = reinterpret_cast<QWidget *>(m_scrollAreaWidgetContents->children().value(i));

			if (widget && (int)widget != (int)m_startPageVerticalLayout)
				delete widget;
		}

		/* Adding new connections buttons */
		for (int i = m_lastConnections.count() - 1; i >= 0 ; i--)
		{
			QStringList list = m_lastConnections.value(i).split('$');
			QString buttonName = QString("%1\\%2\\%3\\%4").arg(list.value(0), list.value(1), list.value(2), list.value(3));

			QCommandLinkButton *lastConnectionButton = new QCommandLinkButton(buttonName);
			lastConnectionButton->setIcon(QIcon(QString::fromUtf8(":/ico/connectdb_ico16.png")));
			connect(lastConnectionButton, SIGNAL(clicked(void)), this, SLOT(recentConnectionButtonClicked(void)));
			m_startPageVerticalLayout->insertWidget(0, lastConnectionButton);
		}
	}

	void MainWindow::addLastConnection(const QString &driver, const QString &sqlEngine, const QString &hostname, const QString &username, const QString &password, const int &port)
	{
		QString connection;

		for (int i=0; i<m_lastConnections.count(); i++)
		{
			if (m_lastConnections.value(i).contains(driver + "$" + sqlEngine + "$" + hostname + "$" + username))
			{
				connection = m_lastConnections.value(i);
				m_lastConnections.removeAt(i);
				break;
			}
		}

		if (connection.length() <= 0)
		{
			connection = QString("%1$%2$%3$%4$%5$").arg(driver, sqlEngine, hostname, username, password);
			connection = connection + QString::number(port);
		}

		m_lastConnections.insert(0, connection);
	}

	void MainWindow::saveLastConnectionList(void)
	{
		QString key;
		QSettings *settings = new QSettings("settings.ini", QSettings::IniFormat);

		settings->setValue(AppSettings::LC_RECENT_CONNECTIONS_NUMBER, m_lastConnections.count());

		for (int i = m_lastConnections.count() - 1; i >= 0; i--)
		{
			key = QString(AppSettings::LC_CONN_STRING).arg(i);
			settings->setValue(key, m_lastConnections.value(i));
		}

		settings->sync();
	}

	void MainWindow::loadLastConnectionList(void)
	{
		QString key;
		QString connectionString;
		QSettings *settings = new QSettings("settings.ini", QSettings::IniFormat);

		int count = settings->value(AppSettings::LC_RECENT_CONNECTIONS_NUMBER, 0).toInt();

		for (int i = 0; i < count; i++)
		{
			key = QString(AppSettings::LC_CONN_STRING).arg(i);
			m_lastConnections.append(settings->value(key, "").toString());
		}
	}

	void MainWindow::addConnection_triggered(void)
	{
		ConnectionDialog dialog(this);
		QString conName;

		if (dialog.exec() == QDialog::Accepted)
		{
			/* Configure connection */
			QSqlError err = connectToSqlServer(dialog.driver(), dialog.sqlEngine() ,dialog.hostName(), dialog.userName(), dialog.password(), dialog.port(), conName);

			if (err.type() == QSqlError::NoError)
			{			
				addConnectionToTree(dialog.driver(), dialog.sqlEngine() ,dialog.hostName(), dialog.userName(), dialog.password(), dialog.port(), conName);
			}
			else
			{
				QMessageBox::warning(this, tr("Unable to open database"), tr("An error occured while opening the connection: ") + err.text());
			}
		}
	}

	void MainWindow::connectionsVisible_triggered(void)
	{
		if (!m_connectionsDockWidget->isVisible())
			m_connectionsDockWidget->show();
		else
			m_connectionsDockWidget->hide();
	}

	void MainWindow::startPageVisible_triggered(void)
	{
		m_tabs->showStartPage();
	}

	void MainWindow::closeConnection_triggered(void)
	{
		QModelIndex current = m_connectionsTreeView->currentIndex();
		DBConnection *connection = reinterpret_cast<DBConnection *>(m_connectionTreeModel->itemFromIndex(current));
	}

	void MainWindow::refreshConnection_triggered(void)
	{
	}

	void MainWindow::tableDetails_triggered(void)
	{
		QModelIndex current = m_connectionsTreeView->currentIndex();
		DBTable *table = reinterpret_cast<DBTable *>(m_connectionTreeModel->itemFromIndex(current));

		m_tabs->addNewTab(table);
	}

	void MainWindow::generateDocumentation_triggered(void)
	{
	}

	void MainWindow::refreshDatabase_triggered(void)
	{
	}

	void MainWindow::connectionsTreeView_clicked(const QModelIndex& index)
	{
	}

	void MainWindow::connectionsTreeView_doubleClicked(const QModelIndex& index)
	{
		DBObject *obj = m_connectionTreeModel->itemFromIndex(index);

		if (obj->objectType() == DBObject::DBOTYPE_TABLE)
		{
			DBTable *table = reinterpret_cast<DBTable *>(obj);
			m_tabs->addNewTab(table);
		}		
	}

	void MainWindow::window_tabsChanged(int count)
	{
		m_tabs->cornerWidget(Qt::TopRightCorner)->setEnabled(m_tabs->count() > 0);
	}

	void MainWindow::exportDoc_clicked(void)
	{
	}

	void MainWindow::showContextMenu(const QPoint &pos)
	{
		QModelIndex current = m_connectionsTreeView->currentIndex();

		DBObject *object = m_connectionTreeModel->itemFromIndex(current);

		if (object && object->objectType() == DBObject::DBOTYPE_CONNECTION)
		{
			if (m_connectionMenu)
				m_connectionMenu->exec(m_connectionsTreeView->mapToGlobal(pos));
		}
		else if (object && object->objectType() == DBObject::DBOTYPE_DATABASE)
		{
			if (m_databaseMenu)
				m_databaseMenu->exec(m_connectionsTreeView->mapToGlobal(pos));
		}
		else if (object && object->objectType() == DBObject::DBOTYPE_TABLE)
		{
			if (m_tableMenu)
				m_tableMenu->exec(m_connectionsTreeView->mapToGlobal(pos));
		}
	}

	void MainWindow::recentConnectionButtonClicked(void)
	{
		if (sender())
		{
			QCommandLinkButton *button = reinterpret_cast<QCommandLinkButton *>(this->sender());
			QString connectionPattern = button->text().replace('\\', '$');
			QString connectionString;

			for (int i=0; i<m_lastConnections.count(); i++)
			{
				if (m_lastConnections.value(i).contains(connectionPattern))
				{
					connectionString = m_lastConnections.value(i);
					break;
				}
			}

			if (connectionString.length() > 0)
			{
				QStringList list = connectionString.split('$');
				QString connName;

				/* Configure connection */
				QSqlError err = connectToSqlServer(list.value(0), list.value(1), list.value(2), list.value(3), list.value(4), list.value(5).toInt(), connName);

				if (err.type() == QSqlError::NoError)
				{			
					addConnectionToTree(list.value(0), list.value(1), list.value(2), list.value(3), list.value(4), list.value(5).toInt(), connName);
				}
				else
				{
					QMessageBox::warning(this, tr("Unable to open database"), tr("An error occured while opening the connection: ") + err.text());
				}
			}
		}	
	}
}
